//-----------------------------------------------------------------------
// <copyright file="ErrorCheckingAcceptanceTest.cs" company="NMock2">
//
//   http://www.sourceforge.net/projects/NMock2
//
//   Licensed under the Apache License, Version 2.0 (the "License");
//   you may not use this file except in compliance with the License.
//   You may obtain a copy of the License at
//
//       http://www.apache.org/licenses/LICENSE-2.0
//
//   Unless required by applicable law or agreed to in writing, software
//   distributed under the License is distributed on an "AS IS" BASIS,
//   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
//   See the License for the specific language governing permissions and
//   limitations under the License.
// </copyright>
// This is the easiest way to ignore StyleCop rules on this file, even if we shouldn't use this tag:
// <auto-generated />
//-----------------------------------------------------------------------
namespace NMock2.AcceptanceTests
{
    using System;
    using System.Runtime.Remoting;
    using System.Text.RegularExpressions;
    using NMock2.Internal;
    using NUnit.Framework;
    using NMock2.Actions;

    [TestFixture]
    public class ErrorCheckingAcceptanceTest : AcceptanceTestBase
    {
        [TestFixtureSetUp]
        public void TestFixtureSetUp()
        {
            SkipVerificationForThisFixture();
        }

		[Test, ExpectedException(typeof(ArgumentException))]
        public void CannotExpectAMethodOnAnRealObject()
        {
            object realObject = new object();
            Expect.Once.On(realObject).Method(NMock2.Is.Anything);
        }

        [Test, ExpectedException(typeof(ArgumentException))]
        public void CannotExpectAMethodThatDoesNotExistInTheMockedType()
        {
            IHelloWorld helloWorld = (IHelloWorld) Mocks.NewMock(typeof(IHelloWorld));

            Expect.Once.On(helloWorld).Method("NonexistentMethod");
        }
        
        [Test, ExpectedException(typeof(ArgumentException))]
        public void CannotExpectAMethodWithAnInvalidName()
        {
            IHelloWorld helloWorld = (IHelloWorld) Mocks.NewMock(typeof(IHelloWorld));

            Expect.Once.On(helloWorld).Method("Invalid Name!");
        }

        [Test, ExpectedException(typeof(ArgumentException))]
        public void CannotExpectGetOfAnInvalidProperty()
        {
            IHelloWorld helloWorld = (IHelloWorld) Mocks.NewMock(typeof(IHelloWorld));

            Expect.Once.On(helloWorld).GetProperty("NonexistentProperty");
        }

        [Test, ExpectedException(typeof(ArgumentException))]
        public void CannotExpectSetOfAnInvalidProperty()
        {
            IHelloWorld helloWorld = (IHelloWorld) Mocks.NewMock(typeof(IHelloWorld));

            Expect.Once.On(helloWorld).SetProperty("NonexistentProperty").To("something");
        }
        
        [Test, ExpectedException(typeof(ArgumentException))]
        public void CannotExpectGetOfIndexerIfNoIndexerInMockedType()
        {
            IHelloWorld helloWorld = (IHelloWorld) Mocks.NewMock(typeof(IHelloWorld));
            
            Expect.Once.On(helloWorld).Get["arg"].Will(Return.Value("something"));
        }

        [Test, ExpectedException(typeof(ArgumentException))]
        public void CannotExpectSetOfIndexerIfNoIndexerInMockedType()
        {
            IHelloWorld helloWorld = (IHelloWorld) Mocks.NewMock(typeof(IHelloWorld));

            Expect.Once.On(helloWorld).Set["arg"].To("something");
        }

        
        [Test, ExpectedException(typeof(ArgumentException))]
        public void CannotExpectAddToNonexistentEvent()
        {
            IHelloWorld helloWorld = (IHelloWorld) Mocks.NewMock(typeof(IHelloWorld));
            
            Expect.Once.On(helloWorld).EventAdd("NonexistentEvent");
        }

        [Test, ExpectedException(typeof(ArgumentException))]
        public void CannotExpectRemoveFromNonexistentEvent()
        {
            IHelloWorld helloWorld = (IHelloWorld) Mocks.NewMock(typeof(IHelloWorld));

            Expect.Once.On(helloWorld).EventRemove("NonexistentEvent", NMock2.Is.Anything);
        }

		public interface IMyHelloWorld
		{
			bool IsPrime(int number);
		}

		//,"You have to set the return value for method 'IsPrime' on 'IMyHelloWorld' mock."
		[Test, ExpectedException(typeof(InvalidOperationException))]
		public void CorrectMessageWhenReturnValueNotSet()
		{
			IMyHelloWorld myHelloWorld = (IMyHelloWorld)Mocks.NewMock(typeof(IMyHelloWorld));

			Expect.Once.On(myHelloWorld).Method("IsPrime");//.Will(Return.Value(true));//, new SetNamedParameterAction("number", 3)); //.With();

			int i = 3;
			bool result = myHelloWorld.IsPrime(i);
		}

		[Test]
		public void NullReturnValue()
		{
			IHelloWorld helloWorld = Mocks.NewMock<IHelloWorld>();

			Expect.Once.On(helloWorld).Method("Ask").Will(Return.Value(null));

			string s = helloWorld.Ask("What?");

			Assert.IsNull(s);
		}

		[Test]
		[ExpectedException(typeof(ArgumentException))]
		public void UnnecessaryReturnValue()
		{
			IHelloWorld helloWorld = Mocks.NewMock<IHelloWorld>();

			Expect.Once.On(helloWorld).Method("Hello").Will(Return.Value("What?"));

			helloWorld.Hello();
		}

		#region Wrong Return Type

		[Test]
		public void WrongReturnType()
		{
			IOperator o = Mocks.NewMock<IOperator>();
			IBase b = Mocks.NewMock<IBase>();

			Expect.Once.On(o).Method("Get").Will(Return.Value(b));

			try
			{
				o.Get();
			}
			catch (ArgumentException e)
			{
				// Make sure that exception message identifies type that was returned, and what was expected
				// (other interfaces will be present in type description, but we don't care too much about them here).
				Assert.IsTrue(Regex.IsMatch(e.Message,
											@".*NMock2\.AcceptanceTests\.ErrorCheckingAcceptanceTest\+IBase.*from a method returning NMock2\.AcceptanceTests\.ErrorCheckingAcceptanceTest\+IChild",
											RegexOptions.IgnoreCase),
								"Exception message wrong: should contain text 'NMock2.AcceptanceTests.ErrorCheckingAcceptanceTest+IBase' as well as text 'from a method returning NMock2.AcceptanceTests.ErrorCheckingAcceptanceTest+IChild' but is: " + e.Message);
			}
		}

		public interface IOperator
		{
			IChild Get();
		}

		public interface IBase
		{}

		public interface IChild : IBase
		{}

		#endregion

		//,"unexpected invocation of eventProvider.AnEvent += <System.EventHandler>\r\nExpected:\r\n"
		[Test]
		[ExpectedException(typeof(ExpectationException))]
		public void UnexpectedEventRegistrationHasUnderstandableMessage()
		{
			IEventProvider eventProvider = Mocks.NewMock<IEventProvider>();

			eventProvider.AnEvent += delegate { };
		}

		//,"unexpected invocation of eventProvider.CustomEvent += <System.EventHandler`1[NMock2.CustomEventArgs]>\r\nExpected:\r\n"
		[Test]
		[ExpectedException(typeof(ExpectationException))]
		public void UnexpectedEventRegistrationHasUnderstandableMessageWithCustomEventArgs()
		{
			IEventProvider eventProvider = Mocks.NewMock<IEventProvider>();

			eventProvider.CustomEvent += delegate { };
		}

		#region MockingInterfaceWithToStringMethodThrowsException

		//,"Interfaces must not contain a declaration for ToString()."
		[Test]
		[ExpectedException(typeof(ArgumentException))]
		public void MockingInterfaceWithToStringMethodThrowsException()
		{
            Mocks.NewMock<InterfaceWithToStringMethod>();
		}

		public interface InterfaceWithToStringMethod
		{
			string ToString();
		}

		#endregion
	}
}
